package com.shallowUniverse.process.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.shallowUniverse.process.context.handler.ProcessFinishedHandler;
import com.shallowUniverse.process.context.handler.ProcessHandlerService;
import com.shallowUniverse.process.context.user.ProcessUserService;
import com.shallowUniverse.process.entity.ProcessNodeDefinition;
import com.shallowUniverse.process.entity.Approval;
import com.shallowUniverse.process.entity.ApprovalDetails;
import com.shallowUniverse.process.exception.ApprovalNotExistException;
import com.shallowUniverse.process.exception.AuthenticationException;
import com.shallowUniverse.process.mapper.ApprovalDetailsMapper;
import com.shallowUniverse.process.service.ProcessNodeDefinitionService;
import com.shallowUniverse.process.service.ApprovalDetailsService;
import com.shallowUniverse.process.service.ApprovalService;
import com.shallowUniverse.process.utils.AssertUtil;
import com.shallowUniverse.process.utils.Builder;
import com.shallowUniverse.process.utils.ProcessUtil;
import com.shallowUniverse.process.utils.Constant;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @author gs
 * @date create in 2020/12/11 16:34
 */
@AllArgsConstructor
public class ApprovalDetailsServiceImpl implements ApprovalDetailsService {

    private final ApprovalDetailsMapper approvalDetailsMapper;
    private final ApprovalService approvalService;
    private final ProcessNodeDefinitionService processNodeDefinitionService;
    private final ProcessHandlerService processHandlerService;
    private final ProcessUserService processUserService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int save(ApprovalDetails approvalDetails) throws ApprovalNotExistException, AuthenticationException {
        //判断是否为空
        if (ObjectUtils.isEmpty(approvalDetails)) {
            return 0;
        }
        //设置默认值
        approvalDetails.setCreateDate(DateUtil.now());
        approvalDetails.setUserId(processUserService.getUserId());
        //查询审批单
        Approval approval = approvalService.findById(approvalDetails.getApprovalId());
        AssertUtil.approvalNotNull(approval);
        //根据当前登录用户角色部门查询节点
        Map<String, String> roleParams = new HashMap<>(2);
        roleParams.put("processId", approval.getProcessId().toString());
        roleParams.put("processNodeRole", ProcessUtil.parseCollectionToString(processUserService.getUserRoles()));
        roleParams.put("deptId", ObjectUtils.nullSafeToString(processUserService.get().getUserDept()));
        List<ProcessNodeDefinition> roleNodeList = processNodeDefinitionService.findMaxNodeByRole(roleParams);
        //判断是否有，如果没有证明没权限
        AssertUtil.notAuthentication(roleNodeList);
        //设置存在于当前审批节点中的节点到审批详情
        approvalDetails.setProcessNodeId(
                roleNodeList
                        .stream()
                        .map(processNodeDefinition -> processNodeDefinition.getId().toString())
                        .filter(approvalDetails.getProcessNodeId()::contains)
                        .collect(Collectors.joining(","))
        );
        //保存审批详情
        int count = approvalDetailsMapper.save(approvalDetails);
        //拿到后置处理器
        ProcessFinishedHandler processFinishedHandler = processHandlerService.generateHandler(approval.getTarget());
        //判断是通过还是驳回
        if (Constant.AUDIT_REFUSE_SIGN.equals(approvalDetails.getInfo())) {
            //修改单子状态为驳回
            approval.setStatus(Constant.PROCESS_REFUSE_SIGN);
            //验证处理器是否存在
            if (!ObjectUtils.isEmpty(processFinishedHandler)) {
                //执行拒绝时的后置处理
                processFinishedHandler.postRefuseHandle(
                        JSON.toJSONString(approvalService.findTableData(approval.getId())), approvalDetails
                );
            }
        } else {
            //查找下一个节点
            List<ProcessNodeDefinition> processNodeDefinitions = processNodeDefinitionService.findByIds(Arrays.stream(approvalDetails.getProcessNodeId().split(",")).map(Long::parseLong).collect(Collectors.toList()));
            List<ProcessNodeDefinition> nextNodes = processNodeDefinitionService.renderNextNode(processNodeDefinitions.get(0));
            //拿到当前节点
            ProcessNodeDefinition currentNode = processNodeDefinitions.get(0);
            //判断是否存在 或 是否需要提前结束流程
            if (CollectionUtils.isEmpty(nextNodes)
                    || ProcessUtil.validate(approval, currentNode, processNodeDefinitionService, approvalService)) {
                //判断是会签还是或签
                if (ObjectUtils.isEmpty(currentNode.getMode()) || Constant.OR.equalsIgnoreCase(currentNode.getMode())
                        || ProcessUtil.ifAllAllowed(processNodeDefinitionService, approvalDetailsMapper, approval, currentNode)) {
                    //证明已经完成流程
                    approval.setStatus(Constant.PROCESS_ALLOW_SIGN);
                    //重置当前节点为当前顺序所有节点
                    ProcessNodeDefinition processNode =
                            Builder.of(ProcessNodeDefinition::new)
                                    .with(ProcessNodeDefinition::setProcessId, approval.getProcessId())
                                    .with(ProcessNodeDefinition::setSeq, currentNode.getSeq())
                                    .build();
                    List<ProcessNodeDefinition> currentNodeList = processNodeDefinitionService.find(processNode);
                    approval.setCurrent(ProcessUtil.joinProcessNodeDefinition(currentNodeList));
                    //验证处理器是否存在
                    if (!ObjectUtils.isEmpty(processFinishedHandler)) {
                        //执行审批通过的后置处理
                        processFinishedHandler.postAllowHandle(
                                JSON.toJSONString(approvalService.findTableData(approval.getId())), approvalDetails
                        );
                    }
                } else {
                    //移除当前审批过的节点
                    //判断是否是最后一个节点
                    if (!CollectionUtils.isEmpty(nextNodes) && !ProcessUtil.validate(approval, currentNode, processNodeDefinitionService, approvalService)) {
                        approval.setCurrent(ProcessUtil.removeNode(approval.getCurrent(), currentNode.getId()));
                    }
                }
            } else {
                //判断是否可以继续往下走流程
                if (ObjectUtils.isEmpty(currentNode.getMode()) || Constant.OR.equalsIgnoreCase(currentNode.getMode())
                        || ProcessUtil.ifAllAllowed(processNodeDefinitionService, approvalDetailsMapper, approval, currentNode)) {
                    //继续往下走流程
                    approval.setCurrent(ProcessUtil.joinProcessNodeDefinition(nextNodes));
                    //清空委派人
                    approval.setAppoint(null);
                } else {
                    //移除当前审批过的节点
                    approval.setCurrent(ProcessUtil.removeNode(approval.getCurrent(), currentNode.getId()));
                }
            }
        }
        //更新审批单
        approvalService.update(approval);
        return count;
    }

    @Override
    public List<ApprovalDetails> find(ApprovalDetails approvalDetails) {
        List<ApprovalDetails> approvalDetailsList = approvalDetailsMapper.selectList(approvalDetails);
        //设置节点名称
        ProcessUtil.populateProcessNodeAndTarget(approvalDetailsList, processNodeDefinitionService);
        //返回
        return approvalDetailsList;
    }

    @Override
    public ApprovalDetails findById(Long id) {
        return approvalDetailsMapper.selectById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int remove(List<Long> ids, boolean isLogic) {
        //判断是否传了id
        if (CollectionUtils.isEmpty(ids)) {
            return 0;
        }
        //判断是做逻辑删除还是直接删除
        if (isLogic) {
            return approvalDetailsMapper.deleteLogic(ProcessUtil.parseCollectionToString(ids));
        } else {
            return approvalDetailsMapper.delete(ProcessUtil.parseCollectionToString(ids));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int removeByApproval(List<Long> approvalIds, boolean isLogic) {
        //判断是否传了id
        if (CollectionUtils.isEmpty(approvalIds)) {
            return 0;
        }
        //判断是做逻辑删除还是真实删除
        if (isLogic) {
            return approvalDetailsMapper.deleteByApprovalLogic(ProcessUtil.parseCollectionToString(approvalIds));
        } else {
            return approvalDetailsMapper.deleteByApproval(ProcessUtil.parseCollectionToString(approvalIds));
        }
    }

    @Override
    public IPage<ApprovalDetails> findPage(IPage<ApprovalDetails> page, ApprovalDetails approvalDetails) {
        IPage<ApprovalDetails> approvalDetailsIPage = approvalDetailsMapper.selectPageList(page, approvalDetails);
        //设置节点名称
        ProcessUtil.populateProcessNodeAndTarget(page.getRecords(), processNodeDefinitionService);
        //返回
        return approvalDetailsIPage;
    }
}
